home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Audio-DSP / NU / Source / MenuManager.m < prev    next >
Encoding:
Text File  |  1993-01-03  |  20.5 KB  |  777 lines

  1.  
  2. /* Generated by Interface Builder */
  3.  
  4. #import "MenuManager.h"
  5. #import "ClassManager.h"
  6. #import "WorkspaceManager.h"
  7. #import "DictManager.h"
  8. #import "GlyphView.h"
  9. #import "NuString.h"
  10. #import "NuWraps.h"
  11. #import "FinderManager.h"
  12. #import "MKManager.h"
  13. #import "InstanceManager.h"
  14. #import "BMList.h"
  15. #import "Terminator.h"
  16. #import "FGWindow.h"
  17. #import "PrefsManager.h"
  18. #import <appkit/Application.h>
  19. #import <appkit/Panel.h>
  20. #import <appkit/Matrix.h>
  21. #import <appkit/ButtonCell.h>
  22. #import <appkit/OpenPanel.h>
  23. #import <appkit/SavePanel.h>
  24. #import <appkit/ScrollView.h>
  25. #import <appkit/Text.h>
  26. #import <appkit/NXBrowser.h>
  27. #import <appkit/NXBrowserCell.h>
  28. #import <defaults/defaults.h>
  29. #import <appkit/Font.h>
  30. #import <objc/error.h>
  31. #import <objc/List.h>
  32. #import <objc/Storage.h>
  33. // #import <objc/zone.h>
  34. // #import <mach/mach_init.h>
  35. #import <dpsclient/psops.h>
  36. #import <streams/streams.h>
  37. #import <libc.h>
  38. #import <strings.h>
  39. #import <ctype.h>
  40. #import <libc.h>
  41. #include <mach.h>
  42. #include <sys/types.h>
  43. #include <sys/stat.h>
  44.  
  45. extern id Nu ; // sole MenuManager instance 
  46.  
  47. // allocate a large, general purpose text buffer
  48. char bigBuf[49152] ;
  49.  
  50. struct loadClass
  51. { char *className ;
  52.   char *dotOFileName ;
  53. } ;
  54.  
  55. const char *NuTypes[] = 
  56. { "Nu",
  57.   NULL 
  58. } ;
  59.  
  60. const char *openTypes[] = 
  61. { "m","Nu","rtf","rtfd",
  62.   NULL 
  63. } ;
  64.  
  65. // procedure to get the next line from a stream
  66. // The newline is included (except at end of file)
  67. void NuGets(NXStream *aStream, char * aBuf)
  68. { int c,i = 0;
  69.   c = NXGetc(aStream) ;
  70.   do
  71.   { if(c == -1) // end of stream
  72.     { aBuf[i] = '\0' ;
  73.       return  ;
  74.     }
  75.     else if(c == '\n')
  76.     { aBuf[i] = c ;
  77.       aBuf[i+1] = '\0' ;
  78.       return ;
  79.     }
  80.     else
  81.     { aBuf[i++] = (char) c ;
  82.       c = NXGetc(aStream) ;
  83.     } 
  84.   } while(1) ;
  85. }
  86.  
  87. @implementation MenuManager
  88.  
  89. - (int) app:sender openFile: (const char *) filename type: (const char *) aType ;
  90. { // respond to remote message to open a file
  91.   const char *fileList[2] ;
  92.   fileList[0] = filename ;
  93.   fileList[1] = NULL ;
  94.   [self openList: fileList path: NULL] ;
  95.   return 1 ;   // YES? NO ? 1?
  96. }
  97.  
  98. - (BOOL) appAcceptsAnotherFile: sender ;
  99. { return YES ;
  100. }
  101.  
  102. - appendFileToTranscript: (char *) fileName ;
  103. { // append the text of the indicated file to the transcript
  104.   char *aStr ;
  105.   struct stat statBuf ;
  106.   int fd ;
  107.   if(!(fd = open(fileName,O_RDONLY)))
  108.   { NXRunAlertPanel("Nu","Cannot open: %c",NULL,NULL,NULL,fileName) ;
  109.     return self ;
  110.   }
  111.   fstat(fd,&statBuf) ;
  112.   aStr = malloc(statBuf.st_size + 1) ;
  113.   read(fd,aStr,statBuf.st_size) ;
  114.   aStr[statBuf.st_size] = '\0' ;
  115.   [self printf: aStr] ;
  116.   close(fd) ;
  117.   free(aStr) ;
  118.   return self ;
  119. }
  120.  
  121.  
  122. - (int)browser:sender fillMatrix:matrix inColumn:(int)column ;
  123. { // delegate method for browser object 
  124.   if(sender == loadedClassesBrowser)
  125.     return [[ClassManager loadList] count] ; 
  126.   return 0 ;
  127. }
  128.  
  129. - browser:sender loadCell:cell atRow:(int)row inColumn:(int)column ;
  130. {  if(sender == loadedClassesBrowser)
  131.    { const char *aClass ;
  132.      [cell setStringValue: [[[ClassManager loadList] objectAt: row] cString]];
  133.      [cell setLeaf:YES] ;
  134.      aClass = [cell stringValue] ;
  135.      if(!strcmp(aClass,"Glyph") || !strcmp(aClass,"Root") 
  136.      || !strcmp(aClass,"Tray") || !strcmp(aClass,"Error"))
  137.      { [cell setSelectable: NO] ;
  138.        [cell setEnabled: NO] ;
  139.      }
  140.    }
  141.    return self ;
  142. }
  143.  
  144.  
  145. - clearTranscript: sender ;
  146. { [transcriptText setText: ""] ;
  147.   return self ;
  148. }
  149.  
  150. - debugWindows: sender ;
  151. { if(glyphView)
  152.     [[glyphView rootGlyph] debugWindows] ;
  153.   return self ;
  154. }
  155.  
  156. - finder: sender ;
  157. { // bring up the Finder panel 
  158.   [finderPanel makeKeyAndOrderFront: self] ;
  159.    [[[NXGetNamedObject("FinderManager",NXApp) 
  160.       findText] controlView] selectText: self] ;
  161.   return self ;
  162. }
  163.  
  164. - findLine: sender ;
  165. { // bring up the Finder panel with the line finder
  166.   // textfield selected
  167.   [finderPanel makeKeyAndOrderFront: self] ;
  168.   [NXGetNamedObject("FinderManager",NXApp) finderCurrent: self] ;
  169.   [[NXGetNamedObject("FinderManager",NXApp) findLine] selectText: self] ;
  170.   return self ;
  171. }
  172.  
  173.  
  174.  
  175. - findNext: sender ;
  176. { [self finder: sender] ;
  177.   [NXGetNamedObject("FinderManager",NXApp) finderNext: sender] ;
  178.   return self ;
  179. }
  180.  
  181. - glyphView: anObject ;
  182. { // set the glyphView iv
  183.   glyphView = anObject ;
  184.   // update instanceManager's instance
  185.   [instanceManager instance: [glyphView targetGlyph]] ;
  186.   return self ;
  187. }
  188.  
  189.  
  190. - glyphManager ;
  191. { // get the glyph manager
  192.   return glyphManager ;
  193. }
  194.  
  195. - glyphManager: sender ;
  196. { // get the glyph browser
  197.   [glyphBrowser makeKeyAndOrderFront: self] ;
  198.   return self ;
  199. }
  200.  
  201. - (NXZone *) glyphZone ;
  202. { // return the default zone used for glyph allocation
  203.   return glyphZone ;
  204. }
  205.  
  206. - glyphView ;
  207. { // returns the current (or most recently) selected glyphView
  208.   return glyphView ;
  209. }
  210.  
  211. - help: sender ;
  212. { // open up a help workspace, "permanently" located in
  213.   // the {NuPath}/workspaces/help.wsd
  214.  return [NXApp showHelpPanel: self] ;
  215. }
  216.  
  217. - hide: sender ;
  218. { [NXApp hide: self] ;
  219.   return self ;
  220. }
  221.  
  222. - (BOOL) inspecting ;
  223. { // return YES iff instance manager is onscreen 
  224.   return [instanceManager isVisible] ;
  225. }
  226.  
  227. - instanceManager ;
  228. { return instanceManager ;
  229. }
  230.  
  231. - instance: sender ;
  232. { // bring instanceManager onscreen
  233.   [instanceManager makeKeyAndOrderFront: self] ;
  234.   return self ;
  235. }
  236.  
  237. - jump: sender ;
  238. { // scroll selection to visible
  239.   id aWin ;
  240.   if([(aWin = [NXApp mainWindow]) isKindOf:
  241.       [WorkspaceManager class]])
  242.   [[aWin textView] scrollSelToVisible] ;
  243.   return self ;
  244. }
  245.  
  246. - loadedClassesBrowser ;
  247. { return loadedClassesBrowser ;
  248. }
  249.  
  250. - mainMenu ;
  251. { return mainMenu ;
  252. }
  253.  
  254. - musicKitManager ;
  255. { // return mKManager object
  256.   return mKManager  ;  
  257. }
  258.  
  259.  
  260. - musicKit: sender ;
  261. { // bring up the music kit config panel 
  262.   [mKPanel makeKeyAndOrderFront: self] ;
  263.   return self ;
  264. }
  265.  
  266.  
  267. - newDictionary:sender ;
  268. { // open a new Dictionary Manager
  269.   [[[NXApp loadNibSection:"DictManager.nib" 
  270.          owner: self] center] makeKeyAndOrderFront: self] ;
  271.     return self;
  272. }
  273.  
  274. - newWorkspace:sender
  275. { // open a new workspace, set its font
  276.   id aWin, aView ;
  277.   aWin =  [[[NXApp loadNibSection:"WorkspaceManager.nib" 
  278.          owner: self] center] makeKeyAndOrderFront: self] ;
  279.   [aWin init] ; // this is SUPPOSED to be called automatically,
  280.   // by loadNibSection:, but it ain't, so I have to
  281.   // do it explicitly
  282.   aView = [[aWin contentView] findViewWithTag: TEXTVIEWTAG] ;
  283.   [aView setFont: 
  284.     [Font
  285.        newFont: NXGetDefaultValue([NXApp appName],"NXFont")
  286.           size: atof(NXGetDefaultValue([NXApp appName],"NXFontSize"))
  287.          style: 0
  288.       matrix: NX_FLIPPEDMATRIX
  289.     ]
  290.   ] ;
  291.   [aView becomeFirstResponder] ;
  292.   return self;
  293. }
  294.  
  295.  
  296.  
  297. - open:sender
  298. { // pop up an open panel. Get
  299.   // the results, open a manager on the code
  300.   id openPanel ;
  301.   openPanel = [OpenPanel new] ;
  302.   [openPanel allowMultipleFiles: YES] ;
  303.   // For some unknown reason, the openPanel must have a
  304.   // delegate if it is to allow "directories", and not
  305.   // just files, to be opened.
  306.   [openPanel setDelegate: self] ;
  307.   if([openPanel runModalForTypes: openTypes])
  308.     [self openList: [openPanel filenames] path: [openPanel directory]] ;
  309.   return self;
  310. }
  311.  
  312. - openList:  (const char * const *) fileNames  path: (const char *) path ;
  313. // open all files in the NULL terminated list of filenames. If
  314. // path is non-null, then it is used as the directory in which to find
  315. // the files.  If null, the fileNames are considered as paths themselves.
  316. { char fName[512], className[128] ;
  317.   id manager ;
  318.   int i ;
  319.   float x = 100.0, y = 800.0 ;
  320.   while(*fileNames != NULL)
  321.   { char *extension ;
  322.     extension = rindex(*fileNames,'.') ;
  323.     if(path)
  324.       sprintf(fName,"%s/%s",path,*fileNames) ;
  325.     else
  326.       strcpy(fName,*fileNames) ;
  327.     if(!strcmp(extension,".Nu"))
  328.     { NXStream *aStream ;
  329.       id aWin ;
  330.       aStream = NXOpenTypedStreamForFile(fName, NX_READONLY) ; 
  331.       aWin = NXReadObject(aStream) ;         
  332.       NXCloseTypedStream(aStream) ;
  333.       glyphView = [[aWin contentView] findViewWithTag: GLYPHVIEWTAG] ;
  334.       [glyphView fileName: fName] ;
  335.       [glyphView setupArchived] ;
  336.       [aWin makeKeyAndOrderFront: self] ;
  337.     }
  338.     else if(!strcmp(extension,".m"))
  339.     { manager = [NXApp loadNibSection:"ClassManager.nib" 
  340.         owner: self] ;
  341.       [manager init] ; // supposed to be called automatically
  342.       // by loadNibSection, but it ain't, so I do it explicitly
  343.       [manager moveTopLeftTo:x :y] ;
  344.       [manager fileName: fName] ;
  345.       x += 25.0 ; y -= 25.0 ;
  346.       [manager makeKeyAndOrderFront: self] ;
  347.       for(i = 0 ; (*fileNames)[i] != '.'; i++)
  348.         className[i] = (*fileNames)[i] ;  // strip off extension 
  349.       className[i] ='\0' ;
  350.       [manager className: className] ;
  351.       [manager readFile] ;
  352.       [manager display] ;
  353.       [manager makeKeyAndOrderFront: self] ;
  354.     }
  355.     else // open anything else as a workspace 
  356.     { manager = [NXApp loadNibSection:"WorkspaceManager.nib" 
  357.         owner: self] ;
  358.      [manager init] ; // supposed to be called automatically
  359.       // by loadNibSection, but it ain't, so I do it explicitly
  360.       [manager fileName: fName] ;
  361.       [manager moveTopLeftTo:x :y] ;
  362.       [manager fileName: fName] ;
  363.       x += 25.0 ; y -= 25.0 ;
  364.       [manager makeKeyAndOrderFront: self] ;
  365.       [manager readFile] ;
  366.      }
  367.     fileNames++ ;
  368.   }
  369.   return self ;
  370. }
  371.  
  372. - preferences: sender ;
  373. { // bring up the preferences panel 
  374.   if(!prefsPanel)
  375.   { [NXApp loadNibSection:"PrefsManager.nib" owner: NXApp] ;
  376.     [prefsPanel setup] ;
  377.     prefsPanel = NXGetNamedObject("PrefsPanel",NXApp) ;
  378.   }
  379.   [prefsPanel makeKeyAndOrderFront: self] ;
  380.   return self ;
  381. }
  382.  
  383. - quit: sender ;
  384. { // before quitting, give user chance last chance
  385.   // to save unsaved documents
  386.   id winList, aWin, *editedWins ;
  387.   int i, knt, editedKnt = 0 ;
  388.   winList = [NXApp windowList] ;
  389.   knt = [winList count] ;
  390.   editedWins = alloca(knt * sizeof(id)) ;
  391.   for(i = 0 ; i < knt ; i++)
  392.   { // first, find all the workspaces and class inspectors
  393.     aWin = [winList objectAt: i] ;
  394.     if([aWin isKindOf: [WorkspaceManager class]] && [aWin isDocEdited])
  395.       editedWins[editedKnt++] = aWin ;
  396.   }
  397.   winList = [GlyphView glyphViewList] ;
  398.   knt = [winList count] ;
  399.   for(i = 0 ; i < knt ; i++)
  400.   { aWin = [[winList objectAt: i] window] ;
  401.     // find all edited glyphViews (except the glyphBrowser)
  402.     if((aWin != glyphBrowser) && [aWin isDocEdited])
  403.       editedWins[editedKnt++] = aWin ;
  404.   }
  405.   // now, if anything was edited:
  406.   if(editedKnt)
  407.   { int rval = NXRunAlertPanel(
  408.       "Quit","%d document%s unsaved changes.\n",
  409.            "Review Unsaved","Quit Anyway","Don't Quit", editedKnt,
  410.       editedKnt > 1 ? "s have" :" has") ;
  411.     if(rval == NX_ALERTDEFAULT)
  412.     { // review all unsaved docs
  413.       for(i = 0 ; i < editedKnt ; i++)
  414.         [editedWins[i] performClose: self] ;
  415.     }
  416.     else if (rval == NX_ALERTOTHER)
  417.        return self ; // abort the quit
  418.     // else rval == NX_ALERTALTERNATE ...just quit
  419.   }
  420.   [NXApp terminate: self] ;
  421.   return self ;
  422. }
  423.  
  424. - setup ;
  425. { id prefsManager ;
  426.   const char *nuPath ;
  427.   struct stat statBuf ;
  428.   // perform initialization
  429.   extern void defSizerCode() ;
  430.   // initialize preferences
  431.   [NXApp loadNibSection:"PrefsManager.nib" owner: NXApp] ;
  432.   prefsPanel = NXGetNamedObject("PrefsPanel",NXApp) ;
  433.   prefsManager = NXGetNamedObject("PrefsManager",NXApp) ;
  434.  
  435.   [prefsManager setup] ;
  436.   if(!strcmp(NXGetDefaultValue([NXApp appName],"NuPath"),""))
  437.     [prefsManager setNuPath] ; // force user to set this
  438.   // now try to verify that NuPath is correct..
  439.   nuPath = NXGetDefaultValue([NXApp appName],"NuPath") ;
  440.   while(stat(nuPath,&statBuf) == -1)
  441.   { [prefsManager setNuPath] ;
  442.     nuPath = NXGetDefaultValue([NXApp appName],"NuPath") ;
  443.   }
  444.   // create zone for allocation glyphs
  445.   glyphZone = NXCreateZone(vm_page_size * 8, vm_page_size * 2, 1) ;
  446.   // load the system classes
  447.   [ClassManager load: "Glyph"] ;
  448.   [ClassManager load: "Error"] ;
  449.   [ClassManager load: "Tray"] ;
  450.   [ClassManager load: "Root"] ;
  451.   // get music kit stuff
  452.   [NXApp loadNibSection:"MKManager.nib" owner: NXApp] ;
  453.   mKPanel = NXGetNamedObject("MKPanel",NXApp) ;
  454.   mKManager = NXGetNamedObject("MKManager",NXApp) ;
  455.   // get the glyph manager
  456.   [NXApp loadNibSection:"GlyphManager.nib" owner: NXApp]  ;
  457.   glyphBrowser = NXGetNamedObject("GlyphBrowser",NXApp) ;
  458.   glyphManager = NXGetNamedObject("GlyphManager",NXApp) ;
  459.   [glyphManager setup] ;
  460.   // load the finder manager
  461.   [NXApp loadNibSection:"FinderManager.nib" owner: NXApp] ;
  462.   finderPanel = NXGetNamedObject("FinderPanel",NXApp) ;
  463.   [NXGetNamedObject("FinderManager",NXApp) init] ;
  464.   // load the instanceManager
  465.   [NXApp loadNibSection:
  466.     "InstanceManager.nib" owner: NXApp] ;
  467.   instanceManager = NXGetNamedObject("InstanceManager",NXApp) ;
  468.   [instanceManager init] ; // supposed to be called automatically
  469.   // by loadNibSection, but it ain't, so I do it explicitly
  470.   return self ;
  471. }
  472.  
  473. - setTranscriptText: anObject ;
  474. { // set the transcript text object and set its
  475.   // font size via defaults database
  476.   transcriptText = [anObject docView] ;
  477.   [transcriptText setFont: 
  478.     [Font
  479.        newFont: NXGetDefaultValue([NXApp appName],"NXFont")
  480.           size: atof(NXGetDefaultValue([NXApp appName],"NXFontSize"))
  481.          style: 0
  482.       matrix: NX_FLIPPEDMATRIX
  483.     ]
  484.   ] ;
  485.   return self ;
  486. }
  487.  
  488. - showLoadedClasses: sender ;
  489. { [loadedClassesBrowser loadColumnZero] ;
  490.   [loadedClassesWindow orderFront: self] ;
  491.   return self ;
  492. }
  493.  
  494. - showPs: sender ;
  495. { // toggle the showps state
  496.   if(showPs)
  497.   { showPs = NO ;
  498.     [[sender selectedCell] setTitle: "Show PS"] ;
  499.   }
  500.   else
  501.   { showPs = YES ;
  502.     [[sender selectedCell] setTitle: "Don't Show PS"] ;
  503.   }
  504.   return self ;
  505. }
  506.  
  507. - showTranscript: sender ;
  508. { [transcriptWindow orderFront: self] ;
  509.   return self ;
  510. }
  511.  
  512. - transcriptText ;
  513. { return transcriptText ;
  514. }
  515.  
  516. - unloadAllclasses: sender ;
  517. { [ClassManager unloadAll] ; 
  518.   return self ;
  519. }
  520.  
  521.  
  522. - unloadSelectedClasses: sender ;
  523. { if([loadedClassesBrowser selectedColumn] == 0)
  524.   { // send unloadClass: to all selected cells
  525.     [[loadedClassesBrowser matrixInColumn: 0] 
  526.       sendAction: @selector(unloadClass:) to: self
  527.       forAllCells: NO] ;
  528.   }
  529.   return self ;
  530. }
  531.  
  532.  
  533. - unloadClass: aCell
  534. { // unload the class which is the stringvalue of aCell.
  535.   // This is called via unloadSelectedClasses:
  536.   [ClassManager unload: [aCell stringValue]] ;
  537.   return self ;
  538. }
  539.  
  540. - windowDidBecomeMain:sender ;
  541. { // delegated from WorkspaceManager.m
  542.   // Short-circuit instance Managers...they are workspaces
  543.   // but they don't have a lineNumBrowser...
  544.   if([[NXApp mainWindow] isKindOf: [InstanceManager class]])
  545.     return self ;
  546.   // otherwise if the mainWindow is a class manager or 
  547.   // a workspace manager...
  548.   if([[NXApp mainWindow] isKindOf: [WorkspaceManager class]])
  549.   { if(finderPanel)
  550.     [[NXGetNamedObject("FinderManager",NXApp) lineNumBrowser] loadColumnZero] ;
  551.   }
  552.   return self ;
  553. }
  554.  
  555. - windowWillClose: sender ;
  556. { // I am the delegate for workspaces and class
  557.   // inspectors...this gets called before they 
  558.   // close. Must deallocate the window's lineList
  559.   if([sender isDocEdited])
  560.   { int rval ;
  561.     char *fileName, untitled[] = "Untitled" ;
  562.     [sender makeKeyAndOrderFront: self] ;
  563.     fileName = [sender fileName] ;
  564.     if(!fileName)
  565.        fileName = untitled ;
  566.     rval = NXRunAlertPanel(
  567.      "Nutation","Save changes to %s?",
  568.      "Save", "Don't Save","Don't Close",fileName) ;
  569.     if(rval == NX_ALERTDEFAULT) 
  570.       [sender save: self] ;
  571.      else if(rval == NX_ALERTOTHER)
  572.       return nil ;
  573.     // else rval == NX_ALERTALTERNATE
  574.   }
  575.   [[sender lineList] free] ;
  576.   [NXApp removeWindowsItem: sender] ;
  577.   return self ;
  578. }
  579.  
  580. /**
  581.  ** "public" methods
  582.  ** accessed by messages to
  583.  ** the global object Nu (sole
  584.  ** instance of class MenuManager!)
  585.  ** The .h defs for these method are in
  586.  ** the file "Nutation.h"
  587.  **/
  588.  
  589.  
  590. - loadIfNeeded: (char *) aClass ;
  591. { // load aClass if it is not already loaded
  592.   if([ClassManager loadIndex:aClass] == -1)
  593.     return [ClassManager load: aClass] ;
  594.   return self ;
  595. }
  596.  
  597. - highLightTarget: (BOOL) YESorNO ;
  598. { return [glyphView highLightTarget: YESorNO] ;
  599. }
  600.  
  601. // glyph access
  602.  
  603. - rootGlyph ;
  604. { // return target of current or most recently
  605.   // selected glyphView
  606.   return [glyphView rootGlyph] ;
  607. }
  608.  
  609. - targetGlyph ;
  610. { // return target of current or most recently
  611.   // selected glyphView
  612.   return [[glyphView rootGlyph] targetGlyph] ;
  613. }
  614.  
  615. - terminator ;
  616. { // return a terminator
  617.   return [Terminator new] ;
  618. }
  619.  
  620. - newGlyphWindow:sender ;
  621. { // open a new Glyph window, return pointer
  622.   // to it's glyphView
  623.   id aWin ;
  624.   aWin = [[NXApp loadNibSection:"GlyphWindow.nib" 
  625.          owner: self] makeKeyAndOrderFront: self] ;
  626.   return [[aWin contentView]findViewWithTag: GLYPHVIEWTAG] ;
  627. }
  628.  
  629.  
  630. - glyphWindow ;
  631. { return [self newGlyphWindow: self] ;
  632. }
  633.  
  634. - printf: (char *) format, ... ;
  635. { // format (as in printf) and print into the transcript
  636.   NXStream *aStream ;
  637.   char *textBuf ;
  638.   int textLen, maxLen ;
  639.   NXSelPt start, end ;
  640.   va_list argList ;
  641.   aStream = NXOpenMemory(NULL, 0, NX_READWRITE) ;
  642.   va_start(argList, format) ;
  643.   NXVPrintf(aStream, format, argList) ;
  644.   va_end(argList) ;
  645.   NXGetMemoryBuffer(aStream, &textBuf, &textLen, &maxLen);
  646.   textLen = [transcriptText textLength] ;
  647.   [transcriptText getSel: &start :&end] ; // remember selection
  648.   [transcriptText setSel: textLen :textLen] ;
  649.   [transcriptText replaceSel: textBuf] ;
  650.   if(start.cp == -1 || start.cp == textLen)
  651.     [transcriptText scrollSelToVisible] ;
  652.   else
  653.     [transcriptText setSel: start.cp :end.cp] ;
  654.   NXCloseMemory(aStream,NX_TRUNCATEBUFFER) ;
  655.   return self ;
  656. }
  657.  
  658. // postscript methods
  659.  
  660. - ps: (char *) format, ... ;
  661. { // format (as in printf) and send to windowserver.
  662.   // Done in a separate context to provide good
  663.   // error handling and recovery.  The idea is stolen
  664.   // from Yap. The separate context is only used
  665.   // if we are not printing.
  666.   // Although "dangerous", the use of vsprint 
  667.   // and bigBuf is so much quicker than using a
  668.   // NXVPrintf and an NXStream that I had to
  669.   // go for it. bigBuf is big, but there is no
  670.   // guarantee it is big enough to hold the
  671.   // result of vprintf. 
  672.   NXStream *errorStream ;
  673.   va_list argList ;
  674.   char *dataBuffer ;
  675.   int len, maxLen, transLen ;
  676.   NXHandler exception;
  677.   static DPSContext NUContext = NULL; // The second context
  678.   DPSContext curContext = DPSGetCurrentContext();
  679.   void SwitchContextsWithFocus() ;
  680.  
  681.   if(!NUContext && (NXDrawingStatus != NX_PRINTING)) // create second context
  682.   { const char *app = [NXApp appName];
  683.     NUContext = DPSCreateContext(NXGetDefaultValue(app, "NXHost"),
  684.         NXGetDefaultValue(app, "NXPSName"), NULL, NULL);
  685.     DPSSetContext(curContext);
  686.   }
  687.   va_start(argList, format) ;
  688.   vsprintf(bigBuf, format, argList) ;
  689.   va_end(argList) ;
  690.   len = strlen(bigBuf) ;
  691.   // make sure this ps code is separated from next ps code
  692.   bigBuf[len++] = '\n' ; 
  693.   if(showPs) 
  694.   { transLen = [transcriptText textLength] ;
  695.     [transcriptText setSel: transLen :transLen] ;
  696.     [transcriptText replaceSel: bigBuf] ;
  697.   }
  698.   if(NXDrawingStatus != NX_PRINTING)
  699.     SwitchContextsWithFocus(NUContext);
  700.   exception.code = 0 ;
  701.   NX_DURING
  702.     if(NXDrawingStatus != NX_PRINTING)
  703.       DPSWriteData(NUContext,bigBuf,len) ;
  704.     else
  705.       DPSWriteData(curContext,bigBuf,len) ;      
  706.     NXPing (); 
  707.   NX_HANDLER
  708.     exception = NXLocalHandler ;
  709.   NX_ENDHANDLER
  710.   if(NXDrawingStatus != NX_PRINTING)
  711.     DPSSetContext(curContext);
  712.   if(exception.code)
  713.   { NXRunAlertPanel("Nu","Postcript errors in message\n"
  714.        "to [ps...] : see transcript",NULL,NULL,NULL) ;
  715.     errorStream = NXOpenMemory(NULL,0,NX_WRITEONLY);
  716.     DPSPrintErrorToStream(errorStream,
  717.        (DPSBinObjSeq) exception.data2);
  718.     NXPrintf(errorStream,"\n\0") ;
  719.     NXFlush(errorStream);
  720.     NXGetMemoryBuffer(errorStream, &dataBuffer, &len, &maxLen);
  721.     [Nu printf: "%s\n", dataBuffer] ;
  722.     NXCloseMemory(errorStream, NX_TRUNCATEBUFFER);
  723.     if(NXDrawingStatus != NX_PRINTING)
  724.     { DPSDestroyContext(NUContext);
  725.       NUContext = NULL;
  726.     }
  727.   }
  728.   return self;
  729. }
  730.  
  731.  
  732. - showString: (char *) aString font: (char *) aFont
  733.       width: (float)width height: (float) height
  734.       x: (float) x y: (float) y ;
  735. { // print aString to currently focused view, using font aFont scaled to [width,height],
  736.   // with origin at x,y
  737.   NPSshowstring(aFont,width,height,x,y,aString) ;
  738.   return self ;
  739. }
  740.  
  741. // music kit parameters
  742.  
  743. - (double) samplingRate ;
  744. { return [mKManager samplingRate] ;
  745. }
  746.  
  747. - (double) beatsPerMinute ;
  748. { return [mKManager beatsPerMinute] ;
  749. }
  750.  
  751. - (double) tickPeriod ;
  752. { return [mKManager tickPeriod] ;
  753. }
  754.  
  755. // bitmap management
  756.  
  757. - bitMapForClass: (char *) aClass size: (NXSize *) aSize ;
  758. { return [BMList newForClass: aClass size: aSize] ;
  759. }
  760.  
  761.  
  762. @end
  763.  
  764. /**
  765.  ** Postscript stuff
  766.  **/
  767. void SwitchContextsWithFocus(DPSContext newContext)
  768. { // borowsed from YAP: switch to newContext in order to
  769.   // protect the main context
  770.   float c1x, c1y, c2x, c2y;
  771.   float winCTM[6];
  772.   int realWinNum;
  773.   GetFocus(&c1x, &c1y, &c2x, &c2y, winCTM, &realWinNum);
  774.   DPSSetContext(newContext);
  775.   ReFocus (realWinNum, winCTM, c1x, c1y, c2x, c2y);
  776. }
  777.